package jwt

import (
	"encoding/json"
	"fmt"
	"gitee.com/xluomo945/fm/helper"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"time"
)

type claims struct {
	Data any
	jwt.RegisteredClaims
}

const (
	tokenPayload = "FM_TOKEN_PAYLOAD"
)

func NewToken(data any) (string, error) {
	if helper.StringEmpty(config.SignKey) {
		return "", fmt.Errorf("jwt sign key is empty")
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, &claims{
		Data: data,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(config.Expire)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
		},
	})
	return token.SignedString([]byte(config.SignKey))
}

func ParseToken(str string) (any, error) {
	if helper.StringEmpty(config.SignKey) {
		return nil, fmt.Errorf("jwt sign key is empty")
	}
	token, e := jwt.ParseWithClaims(str, &claims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(config.SignKey), nil
	})
	if e != nil {
		return nil, e
	}
	if d, ok := token.Claims.(*claims); ok && token.Valid {
		return &d.Data, nil
	}
	return nil, fmt.Errorf("invalid token")
}

func SetPayload(ctx *gin.Context, payload any) {
	ctx.Set(tokenPayload, payload)
}

func GetPayload[T any](ctx *gin.Context) (T, error) {
	var data T
	v, ok := ctx.Get(tokenPayload)
	if !ok {
		return data, fmt.Errorf("token payload is empty")
	}

	j, err := json.Marshal(v)
	if err != nil {
		return data, err
	}

	err = json.Unmarshal(j, &data)
	if err != nil {
		return data, err
	}

	return data, nil
}

func GetJwtToken(ctx *gin.Context) string {
	return config.Token(ctx)
}

func GetUnAuthorizedHttpCode() int {
	return config.HttpCode()
}

func GetUnAuthorizedCode() int {
	return config.Code()
}

func GetUnAuthorizedMessage(err error) string {
	return config.Message(err)
}
